﻿using System;
using System.Windows.Browser;
using System.Collections.Generic;

namespace DeenGames.Utils
{
	///<summary>
	 /// A cookie-based persistent storage provider.
	 ///</summary>
	class CookieStorageProvider : IPersistentStorageProvider
	{

		#region IPersistentStorageProvider Members

        public string Store<_type>(string key, _type value)
		{
			key = PersistentStorageHelper.appIdentifier + key;
			setCookie(key, value);
            return key;
		}

		public _type Retrieve<_type>(string key)
		{
			key = PersistentStorageHelper.appIdentifier + key;
            return getCookie<_type>(key);
		}
        public void Remove(string key)
        {
            this.removeCookie(key);
        }
		public void Clear()
		{
			string[] cookies = HtmlPage.Document.Cookies.Split(';');

			foreach (string cookie in cookies)
			{
				string[] keyValue = cookie.Split('=');
				if (keyValue.Length == 2)
				{
					string key = keyValue[0].ToString();
					removeCookie(key);
				}
			}
		}
        public IEnumerable<string> Keys { get 
        {
            string[] cookies = HtmlPage.Document.Cookies.Split(';');
            foreach (string cookie in cookies)
            {
                string[] keyValue = cookie.Split('=');
                if (keyValue.Length == 2)
                {
                    yield return keyValue[0];
                }
            }
        } }

		#endregion

        ///<summary>
        ///Set the value in the cookie. Throws an exception if setting fails.
        ///</summary>
        private void setCookie<_type>(string key, _type value)
		{
			// We cannot guarantee that the cookie was set (might be too big).
			// We cannot even rely on the value being null, if it was preset.
			// Therefore, check if setting worked by removing the value, setting
			// it, and checking if it's null.
			removeCookie(key);

			// Expire in a year
			DateTime expireDate = DateTime.Now + TimeSpan.FromDays(365);
			string valueAsString = PersistentStorageHelper.Serialize(value);
			string newCookie = key + "=" + valueAsString + ";expires=" + expireDate.ToString("R");
			HtmlPage.Document.SetProperty("cookie", newCookie);

            if (getCookie<_type>(key) == null)
			{
				throw new InvalidOperationException(string.Format("Could not save {0} = {1} because there's no space left in the cookie.", key, value));
			}
		}

		///<summary>
		 /// Delete the value stored for this key in the cookie.
		 /// If we find a way to check if a cookie was set, without removing it,
		 /// setting it, and checking if it's set or removed, then we can 
		 /// delete this function entirely.
		 ///</summary>
		private void removeCookie(string key)
		{
			string newCookie = key + "=;expires=" + DateTime.Now.ToString("R");
			HtmlPage.Document.SetProperty("cookie", newCookie);
		}

		///<summary>
		 /// Get the value stored in the cookie with this key.
		 ///</summary>
		private static _type getCookie<_type>(string key)
		{
			string[] cookies = HtmlPage.Document.Cookies.Split(';');

			foreach (string cookie in cookies)
			{
				string[] keyValue = cookie.Split('=');
				if (keyValue.Length == 2)
				{
					if (keyValue[0].ToString().Trim() == key.Trim())
					{
						return PersistentStorageHelper.Deserialize<_type>(keyValue[1]);
					}
				}
			}

			return default(_type);
		}
	}
}
